package services

import (
	"context"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"gorm.io/gen"
	"mall_frontend_api/biz/dal"
	"mall_frontend_api/biz/dal/memory"
	"mall_frontend_api/biz/handler/base"
	"mall_frontend_api/biz/lib/biz_error"
	"mall_frontend_api/biz/model"
	"mall_frontend_api/biz/model/common"
	"mall_frontend_api/biz/model/product"
	"mall_frontend_api/biz/pack"
	"mall_frontend_api/biz/util"
)

type ProductService struct {
	ctx    context.Context
	common *base.Response
	dao    *dal.InitDAO
}

func NewProductService(ctx context.Context, common *base.Response) *ProductService {
	return &ProductService{
		ctx:    ctx,
		common: common,
		dao:    dal.NewInitDAO(),
	}
}

func (p *ProductService) GetInfo(req *product.GetProductInfoRequest) (*product.Product, error) {
	info, err := p.dao.ProductDAO.GetByConditions(p.ctx, []gen.Condition{
		dal.Product.ID.Eq(req.GetID()),
		dal.Product.Status.Eq(common.ProductStatusPtr(common.ProductStatus_Online)),
	})
	if err != nil {
		return nil, biz_error.NewBizError().SetLogMessage("GetProductInfo err %s", err).SetServerErrorMessage(err.Error())
	}

	categoryMap, err := memory.MGetCategory(p.ctx, info.CategoryID)
	if err != nil {
		return nil, biz_error.NewBizError().SetLogMessage("GetProductInfo MGetCategory err %s", err).SetServerErrorMessage(err.Error())
	}

	productItemList, err := p.dao.ProductItemDAO.GetList(p.ctx, []gen.Condition{dal.ProductItem.ProductID.Eq(req.ID)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductInfo MGetProductItemList err %s", err)
		return nil, err
	}

	productSpecList, err := p.dao.ProductSpecDAO.GetList(p.ctx, []gen.Condition{dal.ProductSpec.ProductID.Eq(req.ID)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductInfo MGetProductSpecList err %s", err)
		return nil, err
	}

	productSpecValueList, err := p.dao.ProductSpecValueDAO.GetList(p.ctx, []gen.Condition{dal.ProductSpecValue.ProductID.Eq(req.ID)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductInfo MGetProductSpecValue err %s", err)
		return nil, err
	}
	return pack.GetProductInfo(info, categoryMap, productItemList, productSpecList, productSpecValueList), nil
}

func (p *ProductService) MGet(req *product.MGetProductRequest) (map[int64]*product.Product, error) {
	dataMap, err := p.dao.ProductDAO.MGet(p.ctx, req.GetIDs())
	if err != nil {
		return nil, biz_error.NewBizError().SetLogMessage("MGetProductInfo err %s", err).SetServerErrorMessage(err.Error())
	}

	var categoryIDs []int64
	for _, d := range dataMap {
		categoryIDs = append(categoryIDs, d.CategoryID)
	}

	categoryMap, err := memory.MGetCategory(p.ctx, util.Unique(categoryIDs)...)
	if err != nil {
		return nil, biz_error.NewBizError().SetLogMessage("MGetProductInfo MGetCategory err %s", err).SetServerErrorMessage(err.Error())
	}

	productItemList, err := p.dao.ProductItemDAO.GetList(p.ctx, []gen.Condition{dal.ProductItem.ProductID.In(util.Unique(req.IDs)...)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductItemList err: %v", err)
		return nil, err
	}

	var productItemMap = make(map[int64][]*model.ProductItem)
	for _, item := range productItemList {
		productItemMap[item.ProductID] = append(productItemMap[item.ProductID], item)
	}

	productSpecList, err := p.dao.ProductSpecDAO.GetList(p.ctx, []gen.Condition{dal.ProductSpec.ProductID.In(req.IDs...)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductSpecList error: %v", err)
		return nil, err
	}

	productSpecValueList, err := p.dao.ProductSpecValueDAO.GetList(p.ctx, []gen.Condition{dal.ProductSpecValue.ProductID.In(req.IDs...)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductSpecValue error: %v", err)
		return nil, err
	}

	return pack.MGetProduct(dataMap, categoryMap, productItemList, productSpecList, productSpecValueList), nil
}

func (p *ProductService) GetList(req *product.GetProductListRequest) ([]*product.Product, int64, error) {
	var where []gen.Condition
	reqCategoryIDs := util.String2Int64Array(req.CategoryIDs)
	if len(reqCategoryIDs) > 0 {
		where = append(where, dal.Product.CategoryID.In(reqCategoryIDs...))
	}

	list, total, err := p.dao.ProductDAO.GetListWithTotal(p.ctx, &dal.ProductListParams{
		Condition: where,
		Page:      p.common.GetPage(),
		Size:      p.common.GetSize(),
	})
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductListWithTotal error: %v", err)
		return nil, 0, err
	}
	var categoryIDs []int64
	var productIDs []int64
	for _, m := range list {
		categoryIDs = append(categoryIDs, m.CategoryID)
		productIDs = append(productIDs, m.ID)
	}
	productMap, err := p.dao.CategoryDAO.MGet(p.ctx, util.Unique(categoryIDs))
	if err != nil {
		hlog.CtxErrorf(p.ctx, "MGetCategory error: %v", err)
		return nil, 0, err
	}

	productSpecList, err := p.dao.ProductSpecDAO.GetList(p.ctx, []gen.Condition{dal.ProductSpec.ProductID.In(productIDs...)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductSpecList error: %v", err)
		return nil, 0, err
	}

	productSpecValueList, err := p.dao.ProductSpecValueDAO.GetList(p.ctx, []gen.Condition{dal.ProductSpecValue.ProductID.In(productIDs...)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductSpecValue error: %v", err)
		return nil, 0, err
	}

	productItemList, err := p.dao.ProductItemDAO.GetList(p.ctx, []gen.Condition{dal.ProductItem.ProductID.In(util.Unique(productIDs)...)}, 0, 0)
	if err != nil {
		hlog.CtxErrorf(p.ctx, "GetProductItemList err: %v", err)
		return nil, 0, err
	}

	return pack.GetProductList(list, productMap, productItemList, productSpecList, productSpecValueList), total, nil
}
